/*
 * This file is Copyright 2002-2006 Loyola University Chicago,
 * Department of Computer Science and the Emerging Technologies Laboratory.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License via
 *    http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.citep.web.admin.accounts.client;

import java.util.ArrayList;
import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.History;

import com.citep.web.gwt.dto.*;
import com.citep.web.gwt.cache.*;
//import com.citep.web.gwt.widgets.DynaTableDataProvider.RowDataAcceptor;


public class AccountListApplication {
	
	protected AsyncCallback categoryListCallback;
	protected AsyncCallback checkTransactionTimeCallback;
	protected ArrayList currentList; //list with accounts being currently displayed
	protected AccountTreeCache cache = AccountTreeCache.getCache();
	
	protected AccountTreeNode accountChart = null;

	//use this to make sure we are displaying the latest transaction balances
	private Date latestTransactionTime;
	
	protected void checkBalances() {
		accountsService.getLatestTransactionTime(getCheckTransactionTimeCallBack());
		System.out.println("checking balances");
	}
	
	protected AsyncCallback getCheckTransactionTimeCallBack() {
		if(checkTransactionTimeCallback == null) {
			checkTransactionTimeCallback = new AsyncCallback() {
				public void onSuccess(Object result) {
					Date serverTime = (Date)result;
					System.out.println("Times: " + serverTime + " vs. " + latestTransactionTime);
					if(serverTime != null && !serverTime.equals(latestTransactionTime)) {
						//if new transactions have been added/modified,
						//force a reload of the cache and update the balances
						//displayed on the tree						
						cache.getAccountTree(new AccountTreeListenerAdapter() {
							public void onAccountTreeReady(AccountTreeNode node) {
								accountChart = node;
								System.out.println("REFRESHING DETAILS");
								presentation.refreshAccountDetails(accountChart);
								presentation.setReadyState();
							}
							public void onAccountTreeLoadFailure(Throwable t) {
								presentation.displayError("", t.getMessage());
								presentation.setReadyState();
							}							
						},true,true);
						
						latestTransactionTime = serverTime;
					} else {
						presentation.setReadyState();
					}
					
				}
				
				public void onFailure(Throwable caught) {
					processException(caught);
					presentation.setReadyState();
				}		
			};
		}
		
		return checkTransactionTimeCallback;
	}
	
	protected void refreshAccountTree() {
		
		presentation.setLoadingState();
		
		//only forces a load call to onAccountTreeReady the first time
		boolean forceCall = (accountChart == null);
		
		cache.getAccountTree(new AccountTreeListener() {
			public void onAccountTreeReady(AccountTreeNode node) {
				accountChart = node;
				presentation.refreshAccountTree(accountChart);
				presentation.setReadyState();
			}
			public void onAccountTreeLoadFailure(Throwable t) {
				presentation.displayError("", t.getMessage());
				presentation.setReadyState();
			}
			
			public void onAccountTreeCurrent() {
				//we have the current tree, so
				//make sure the balances are up to date
				checkBalances();
			}
			
		},forceCall);
	}

	protected AccountListPresentation presentation;

	protected AccountServiceAsync accountsService; 
	
	public AccountListApplication() {
		accountsService = (AccountServiceAsync)GWT.create(AccountService.class);
		((ServiceDefTarget)accountsService).setServiceEntryPoint(GWT.getModuleBaseURL() + "/accounts");
	}
	
	public void setPresentation(AccountListPresentation presentation) {
		this.presentation = presentation;
	}	

	protected void processException(Throwable caught) {
		
		String msg = caught.getMessage();

		if(msg.substring(0, 2).equals("__")) {
			
			/*
			 * We must make sure that we cover the case where the string ends in __
			 * or not, since GWT's javascript version of String.split() works different
			 * than java's String.split() for empty tokens.
			 */
			String [] tokens;
			if(msg.substring(msg.length()-2, msg.length()).equals("__"))
				tokens = msg.substring(2,msg.length()-2).split("__");
			else
				tokens = msg.substring(2,msg.length()).split("__");
			
			String type = tokens[0];
			
			if(type.equals("validation")) {
				
				//there most be an even number of tokens (key:value pairs)
				if((tokens.length - 1) % 2 == 0) {
					
					for(int i = 1; i < tokens.length; i += 2) {
						String key = tokens[i];
						String value = tokens[i+1];
						presentation.displayError(key,value);
					}
				}
			} else {
				presentation.displayStatus(caught.getMessage(), 10);
				caught.printStackTrace();
			}
		} else {
			presentation.displayStatus(caught.getMessage(), 10);
			caught.printStackTrace();
		}
		
		
	}
	
	
	public void refreshAccountList() {
		//presentation.getDataGrid().refresh();
		
	}
	
	public void refreshCategoryList() {
		accountsService.getAccountCategories(getCategoryListCallback());
	}

	protected AsyncCallback getCategoryListCallback() {
		if(categoryListCallback == null) {
			categoryListCallback = new AsyncCallback() {
				public void onSuccess(Object result) {
					ArrayList categoryList = (ArrayList)result;
					for(int i = 0; i < categoryList.size(); i++) {
						AccountCategoryDTO category = (AccountCategoryDTO)categoryList.get(i);
						presentation.addShortCut(new CategoryShortcut(category.getName(),category.getId()), true);
					}
				}
				
				public void onFailure(Throwable caught) {
					processException(caught);
				}
			};
		}
		
		return categoryListCallback;
	}
	
	public void onAccountClicked(AccountDTO account) {
		String token = HistoryEncoder.encode("transaction_entry", new Integer(account.getId()));
		History.newItem(token);

	}
}
